#include "glviewport.h"


#define VERTEXIN 0
#define TEXTUREIN 1

GLViewport::GLViewport(QWidget *parent)
    :QOpenGLWidget(parent)
{

}

void GLViewport::initializeGL()
{
    initializeOpenGLFunctions();
    glEnable(GL_DEPTH_TEST);

    static const GLfloat vertices[] = {
        //顶点坐标
                -1.0f,-1.0f,
                -1.0f,+1.0f,
                +1.0f,+1.0f,
                +1.0f,-1.0f,
                //纹理坐标
                0.0f,1.0f,
                0.0f,0.0f,
                1.0f,0.0f,
                1.0f,1.0f,
    };

    m_vbo.create();
    m_vbo.bind();
    m_vbo.allocate(vertices, sizeof(vertices));
    m_pProgram = new  QOpenGLShaderProgram(this);
    if(!m_pProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/yuv422.vsh"))
        exit(-1);
    if(!m_pProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/yuv422.fsh"))
        exit(-1);

    // 绑定输入坐标点和纹理属性
    m_pProgram->bindAttributeLocation("vertexIn", VERTEXIN);
    m_pProgram->bindAttributeLocation("textureIn", TEXTUREIN);
    if(!m_pProgram->link())
        exit(-1);
    if(!m_pProgram->bind()){
        exit(-1);
    }

    m_pProgram->enableAttributeArray(VERTEXIN);
    m_pProgram->enableAttributeArray(TEXTUREIN);
    m_pProgram->setAttributeBuffer(VERTEXIN, GL_FLOAT, 0, 2, 2 * sizeof(GL_FLOAT));
    m_pProgram->setAttributeBuffer(TEXTUREIN, GL_FLOAT, 8 * sizeof(GLfloat), 2, 2 * sizeof(GL_FLOAT));

    m_textureUniformY = m_pProgram->uniformLocation("tex_y");
    m_textureUniformU = m_pProgram->uniformLocation("tex_u");
    m_textureUniformV = m_pProgram->uniformLocation("tex_v");

    m_pTextureY = new QOpenGLTexture(QOpenGLTexture::Target2D);
    m_pTextureU = new QOpenGLTexture(QOpenGLTexture::Target2D);
    m_pTextureV = new QOpenGLTexture(QOpenGLTexture::Target2D);

    m_pTextureY->create();
    m_pTextureU->create();
    m_pTextureV->create();

    m_idY = m_pTextureY->textureId();
    m_idU = m_pTextureU->textureId();
    m_idV = m_pTextureV->textureId();

    glClearColor(0.0,0,0,0);
//    initTexture();
//    initShaders();
}

void GLViewport::resizeGL(int w, int h)
{ makeCurrent();
    glViewport(0,0,w,h);
     doneCurrent();
//       qreal aspect = qreal(w) / qreal(h ? h : 1);
//       const qreal zNear = 3.0, zFar = 7.0, fov = 45.0;
//       projection.setToIdentity();
//       projection.perspective(fov, static_cast<float>(aspect), zNear, zFar);

}

void GLViewport::paintGL()
{
//    return;
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_idY);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_currentFrame.width, m_currentFrame.height, 0, GL_RED, GL_UNSIGNED_BYTE, m_currentFrame.dataY);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, m_idU);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_currentFrame.width>>1, m_currentFrame.height, 0, GL_RED, GL_UNSIGNED_BYTE, m_currentFrame.dataU);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, m_idV);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_currentFrame.width>>1, m_currentFrame.height, 0, GL_RED, GL_UNSIGNED_BYTE, m_currentFrame.dataV);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glUniform1i(m_textureUniformY, 0);
    glUniform1i(m_textureUniformU, 1);
    glUniform1i(m_textureUniformV, 2);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}

void GLViewport::updateImage(const QImage& img)
{
//    m_pTexture->release();
//    m_pTexture->destroy();
//    m_pTexture->create();
//    m_pTexture->setData(img);
//    m_pTexture->setLevelofDetailBias(-1);
    update();
}

void GLViewport::updateYuv422(quint8 *dataY, quint8 *dataU, quint8 *dataV, int width, int height)
{
    m_currentFrame.dataY = dataY;
    m_currentFrame.dataU = dataU;
    m_currentFrame.dataV = dataV;
    m_currentFrame.width = width;
    m_currentFrame.height = height;
    update();
}

void GLViewport::initShaders()
{
//    texCoords.append(QVector2D(0,1));
//    texCoords.append(QVector2D(1,1));
//    texCoords.append(QVector2D(0,0));
//    texCoords.append(QVector2D(1,0));

//    vertices.append(QVector3D(-1, -1, 1));
//    vertices.append(QVector3D(1, -1, 1));
//    vertices.append(QVector3D(-1, 1, 1));
//    vertices.append(QVector3D(1, 1, 1));

    QOpenGLShader * vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
    const char* vsrc = "attribute vec4 vertex;\n"
                       "attribute vec2 texCoord;\n"
                       "varying vec2 texc;\n"
                       "void main(void)\n"
                       "{\n"
                       "    gl_Position = vertex;\n"
                       "    texc = texCoord;\n"
                       "}\n";
    vshader->compileSourceCode(vsrc);

    QOpenGLShader* fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
    const char* fsrc =  "uniform sampler2D texture;\n"
                        "varying vec2 texc;\n"
                        "void main(void)\n"
                        "{\n"
                        "    gl_FragColor = texture2D(texture,texc);\n"
                        "}\n";
    fshader->compileSourceCode(fsrc);

//    program.addShader(vshader);
//    program.addShader(fshader);
//    program.bindAttributeLocation("vertex", 0);
//    program.bindAttributeLocation("texCoord", 1);

//    if(!program.link())
//        close();
//    if(!program.bind())
//        close();
}

void GLViewport::initTexture()
{
//    m_pTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
//    m_pTexture->setMinificationFilter(QOpenGLTexture::Nearest);
//    m_pTexture->setMagnificationFilter(QOpenGLTexture::Linear);
//    m_pTexture->setWrapMode(QOpenGLTexture::ClampToBorder);
////    m_pTexture->setSize(this->width(), this->height());
//     m_pTexture->setSize(1920, 1080);
//    m_pTexture->allocateStorage();
}
